package com.dc.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.dc.common.DateUtil;
import com.dc.common.ResponseResultVO;
import com.dc.entity.Region;
import com.dc.feign.SystemApiServiceFeign;
import com.dc.mapper.DeviceHistoryLogMapper;
import com.dc.mapper.DeviceMapper;
import com.dc.mapper.RegionMapper;
import com.dc.model.Device;
import com.dc.model.DeviceHistoryLog;
import com.dc.service.HomeScreenService;
import com.dc.util.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;

@Service
public class HomeScreenServiceImpl implements HomeScreenService {

    @Resource
    private SystemApiServiceFeign systemFeign;
    @Resource
    private DeviceMapper deviceMapper;
    @Resource
    private RegionMapper regionMapper;
    @Resource
    private DeviceHistoryLogMapper historyLogMapper;

    @Override
    public ResponseResultVO analogAlarm() {
        Device device = null;
        List<Device> deviceList = deviceMapper.selectList(new QueryWrapper<Device>().lambda().eq(Device::getDeviceStatus, 0));
        if (CollectionUtils.isNotEmpty(deviceList)) {
            device = deviceList.get(0);
            device.setDeviceStatus(1);
            deviceMapper.updateById(device);
        }
        return systemFeign.sendWebsocketMessage(JSON.toJSONString(device), null);
    }

    /**
     * 数量统计
     *
     * @return
     */
    @Override
    public ResponseResultVO deviceNumberStatistical() {
        Map<String, Object> result = new HashMap<>(3);
        // 总设备数量
        List<Device> devices = deviceMapper.selectList(new QueryWrapper<>());
        HashMap<String, Object> hashMap = new HashMap<>(4);
        hashMap.put("allDeviceNum", devices.size());
        long num = devices.stream().filter(cc -> 1 != cc.getDeviceStatus()).count();
        hashMap.put("onlineDeviceNum", num);
        // 在线率
        hashMap.put("onlineRate", new BigDecimal(num).divide(new BigDecimal(devices.size()), 2, BigDecimal.ROUND_HALF_UP)
                .multiply(new BigDecimal(100)).intValue() + "%");

        // 正常运行设备数量
        hashMap.put("normallyDeviceNum", devices.stream().filter(cc -> 0 == cc.getDeviceStatus()).count());

        // 预警数据
        LambdaQueryWrapper<DeviceHistoryLog> wrapper = new LambdaQueryWrapper<>();
        hashMap.put("alarmNum", historyLogMapper.selectList(wrapper).stream().filter(cc -> cc.getDeviceStatus() > 3 && cc.getDeviceStatus() < 6).count());
        /// hashMap.put("alarmNum", devices.stream().filter(cc -> cc.getDeviceStatus() > 3 && cc.getDeviceStatus() < 6).count());

        // 今日预警数据
        LambdaQueryWrapper<DeviceHistoryLog> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.apply("  DATE_FORMAT(alarm_time,'%Y-%m-%d') = CURRENT_DATE()");
        hashMap.put("todayAlarmNum", historyLogMapper.selectList(lambdaQueryWrapper).stream().filter(cc -> cc.getDeviceStatus() > 3 && cc.getDeviceStatus() < 6).count());

        /*String date = DateUtil.parseDateToStr(new Date(), DateUtil.DATE_FORMAT_YYYY_MM_DD);
        List<Device> todayList = deviceMapper.selectList(new LambdaQueryWrapper<Device>()
                .ge(Device::getAlarmTime, date + " 00:00:00").le(Device::getAlarmTime, date + " 23:59:59"));
        hashMap.put("todayAlarmNum", todayList.stream().filter(cc -> cc.getDeviceStatus() > 3).count());*/

        // 最上面一层
        result.put("onTop", hashMap);

        //////////////////////////////////////////////////////////////////////////////////

        // 区域接入设备数量
        List<Device> deviceList = deviceMapper.selectList(new QueryWrapper<>());
        Map<Long, Long> longLongMap = deviceList.stream()
                .filter(cc -> (null != cc.getRegionId()))
                .collect(Collectors.groupingBy(Device::getRegionId, Collectors.counting()));
        List<Region> regionList = regionMapper.selectList(new QueryWrapper<>());
        Map<String, Long> collectMap = new HashMap<>(6);
        for (Map.Entry<Long, Long> entry : longLongMap.entrySet()) {
            for (Region region : regionList) {
                if (entry.getKey().equals(region.getId())) {
                    collectMap.put(region.getRegionName(), entry.getValue());
                }
            }
        }
        HashMap<String, Object> midMap = new HashMap<>(2);
        midMap.put("xVal", collectMap.keySet());
        midMap.put("yVal", collectMap.values());
        result.put("midLet", midMap);

        // 各类型设备数据
        List<Map<String, Object>> midRightList = new ArrayList();
        Map<String, Long> longMap = deviceList.stream()
                .filter(cc -> (null != cc.getDeviceType() && StringUtils.isNotBlank(cc.getDeviceType())))
                .collect(Collectors.groupingBy(Device::getDeviceType, Collectors.counting()));

        AtomicLong l = new AtomicLong(1);
        longMap.entrySet().stream().sorted((x, y) -> {
            return y.getValue().compareTo(x.getValue());
        }).forEach(entry -> {
            Map<String, Object> val = new HashMap<>(3);
            val.put("sort", l.get());
            val.put("name", entry.getKey());
            val.put("value", longMap.get(entry.getKey()));
            midRightList.add(val);
            l.incrementAndGet();
        });
        result.put("midRight", midRightList);

        //////////////////////////////////////////////////////////////////////////////////
        // 今日 = 预警/故障信息走势
        List<DeviceHistoryLog> logList = historyLogMapper.selectList(lambdaQueryWrapper);

        // 预警/故障信息走势
        logList.stream().forEach(cc -> {
            // 时间格式化
            cc.setTimeRemark(DateUtil.parseDateToStr(cc.getAlarmTime(), "MM-dd HH:00"));
        });
        // 分组，并且排序
        Map<String, List<DeviceHistoryLog>> collect = logList.stream()
                .collect(Collectors.groupingBy(DeviceHistoryLog::getTimeRemark))
                .entrySet().stream()
                .sorted(Map.Entry.comparingByKey())
                .collect(Collectors.toMap(
                        Map.Entry::getKey,
                        Map.Entry::getValue,
                        (oldValue, newValue) -> oldValue, LinkedHashMap::new));

        // 时间数组
        String[] times = {"00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23"};
        String day = DateUtil.parseDateToStr(new Date(), "MM-dd ");

        Map bottomMap = new HashMap(3);

        // y轴 数据
        LinkedList<Integer> alarmNumYVal = new LinkedList<>();
        LinkedList<Integer> faultNumYVal = new LinkedList<>();
        collect.values().forEach(cc -> {
            AtomicInteger atomicAlarm = new AtomicInteger(0);
            AtomicInteger atomicFault = new AtomicInteger(0);
            if (null != cc) {
                cc.stream().forEach(tt -> {
                    if (tt.getDeviceStatus() > 3 && tt.getDeviceStatus() < 6) {
                        atomicAlarm.incrementAndGet();
                    }
                    if (tt.getDeviceStatus() == 1) {
                        atomicFault.incrementAndGet();
                    }
                });
            }
            alarmNumYVal.add(atomicAlarm.get());
            faultNumYVal.add(atomicFault.get());
        });

        LinkedList<String> strings = new LinkedList<>(collect.keySet());
        for (int i = 0; i < times.length; i++) {
            String newDay = day + times[i] + ":00";
            if (i > strings.size() || i == strings.size()) {
                strings.add(newDay);
                alarmNumYVal.add(0);
                faultNumYVal.add(0);
            } else {
                if (!strings.get(i).equals(newDay)) {
                    strings.add(i, newDay);
                    alarmNumYVal.add(i, 0);
                    faultNumYVal.add(i, 0);
                }
            }
        }
        bottomMap.put("xVal", strings);
        bottomMap.put("alarmNumYVal", alarmNumYVal);
        bottomMap.put("faultNumYVal", faultNumYVal);

        // 底部
        result.put("bottom", bottomMap);

        return ResponseResultVO.successResult(result);
    }
}
